In [1]:
%matplotlib inline
import math
from matplotlib import pyplot as plt
from IPython.display import display, Javascript
from image_labelling_tool import labelling_tool, labelling_tool_jupyter
In [2]:
display(Javascript(labelling_tool_jupyter.LABELLING_TOOL_JUPYTER_JS))
The kernel-side widget model is defined in the ImageLabellingTool
class in the labelling_tool
module.
Note: the 'Loading...' screen may persist for a while initially; this is because the client-side tool is waiting for the notebook to finish executing all the cells below so it can get round to sending the label data to the client.
In [3]:
# Specify our 3 label classes.
# `LabelClass` parameters are: symbolic name, human readable name for UI, and RGB colour as list
label_classes = [labelling_tool.LabelClass('tree', 'Trees', [0, 255, 192]),
labelling_tool.LabelClass('building', 'Buldings', [255, 128, 0]),
labelling_tool.LabelClass('lake', 'Lake', [0, 128, 255]),
]
# Define the tool dimensions
TOOL_WIDTH, TOOL_HEIGHT = 980, 480
# Load in .JPG images from the 'images' directory.
labelled_images = labelling_tool.PersistentLabelledImage.for_directory('images', image_filename_pattern='*.jpg')
print 'Loaded {0} images'.format(len(labelled_images))
labelling_tool_config = {
'tools': {
'imageSelector': True,
'labelClassSelector': True,
'drawPolyLabel': True,
'compositeLabel': True,
'deleteLabel': True
}
}
# Create the labelling tool IPython widget and display it
labeller = labelling_tool_jupyter.ImageLabellingTool(labelled_images=labelled_images, label_classes=label_classes,
tool_width=TOOL_WIDTH, tool_height=TOOL_HEIGHT,
labelling_tool_config=labelling_tool_config)
display(labeller)
To navigate between images:
To move around images:
To label regions of the image:
In [4]:
labelled_img = labelled_images[1]
In [5]:
labels_2d = labelled_img.render_labels(label_classes=['tree', 'building', 'lake'], pixels_as_vectors=False)
plt.imshow(labels_2d, cmap='gray')
plt.show()
Re-ordering changes the label values:
In [6]:
labels_2d = labelled_img.render_labels(label_classes=['lake', 'building', 'tree'], pixels_as_vectors=False)
plt.imshow(labels_2d, cmap='gray')
plt.show()
You can render a subset of the labels used in the image; just the trees:
In [7]:
labels_2d = labelled_img.render_labels(['tree'], pixels_as_vectors=False)
plt.imshow(labels_2d, cmap='gray')
plt.show()
Each item in label_classes
can also be a list of classes. This will result in the same value being used for multiple classes in the image. Lets render the natural featues - lake and trees - as one value and the non-natural - buildings - as another:
In [8]:
labels_2d = labelled_img.render_labels(label_classes=[['tree', 'lake'], 'building'], pixels_as_vectors=False)
plt.imshow(labels_2d, cmap='gray')
plt.show()
Setting the fill
parameter to False
results in outlines being rendered:
In [9]:
labels_2d = labelled_img.render_labels(label_classes=['tree', 'building', 'lake'], pixels_as_vectors=False, fill=False)
plt.figure(figsize=(8,6))
plt.imshow(labels_2d)
plt.show()
Setting the pixels_as_vectors
parameter to True
will result in a multi-channel image in the form of a 3D array. It will have one channel for each item in label_classes
. Pixels will have either a value of 0
or 1
in a given channel indicating presence of a label in that class:
In [10]:
labels_2dn = labelled_img.render_labels(label_classes=['tree', 'building', 'lake'], pixels_as_vectors=True)
plt.figure(figsize=(16,4))
# trees
plt.subplot(1,3,1)
plt.imshow(labels_2dn[:,:,0], cmap='gray')
# buildings
plt.subplot(1,3,2)
plt.imshow(labels_2dn[:,:,1], cmap='gray')
# lake
plt.subplot(1,3,3)
plt.imshow(labels_2dn[:,:,2], cmap='gray')
plt.show()
The render_individual_labels
method assigns a different label value to each individual object. It returns a multi-channel image as a 3D array and a the gives the number of labels in each channel. The label_classes
parameter functions as with the render_labels
method.
In [11]:
labels_2dn, label_count = labelled_img.render_individual_labels(label_classes=['tree', 'building', 'lake'])
print 'Label count={0}'.format(label_count)
plt.figure(figsize=(16,4))
# trees
plt.subplot(1,3,1)
plt.imshow(labels_2dn[:,:,0])
# buildings
plt.subplot(1,3,2)
plt.imshow(labels_2dn[:,:,1])
# lake
plt.subplot(1,3,3)
plt.imshow(labels_2dn[:,:,2])
plt.show()
Setting the fill
parameter to False
results in an outline image as before:
In [12]:
# Only render trees so that we can show one large image, otherwise the 1-pixel-wide outlines
# will be difficult to see:
labels_2dn, label_count = labelled_img.render_individual_labels(label_classes=['tree'],
fill=False)
print 'Label count={0}'.format(label_count)
plt.figure(figsize=(12,9))
plt.imshow(labels_2dn[:,:,0])
plt.show()
The extract_label_images
method extracts the pixels covered by each individual labelled object from the original image. The label_class_set
parameter specifies the classes of objects that should be rendered; objects whoses classes are not listed are not rendered. It can also be None
to render all objects of all classes. It returns a list of images:
In [13]:
# Render all objects:
object_images = labelled_img.extract_label_images(label_class_set=None)
n_cols = 4
n_rows = int(math.ceil(float(len(object_images)) / n_cols))
plt.figure(figsize=(16,n_rows*3))
for i, img in enumerate(object_images):
plt.subplot(n_rows, n_cols, i + 1)
plt.imshow(img)
plt.show()
Extract objects separately by class:
In [14]:
for cls in ['tree', 'lake', 'building']:
print 'Extracted objects of class \'{0}\':'.format(cls)
object_images = labelled_img.extract_label_images(label_class_set=[cls])
n_cols = 4
n_rows = int(math.ceil(float(len(object_images)) / n_cols))
plt.figure(figsize=(16,n_rows*3))
for i, img in enumerate(object_images):
plt.subplot(n_rows, n_cols, i + 1)
plt.imshow(img)
plt.show()
The label data is in JSON form. An example file is included in the images
directory. The format of the file will now be described.
<root>:
{
image_filename: <image filename as string>
labels: [
<label_object 0>,
<label_object 1>,
...
<label_object N>
]
}
<label_object -- where label_type=polygon>:
{
label_class: <label class as string; identifiers used above to identify label classes>
label_type: 'polygon',
vertices: [
<vertex 0>,
<vertex 1>,
...
<vertex N>
]
}
<vertex>:
{
x: <x-co-ordinate as float>,
y: <y-co-ordinate as float>
}